package ext.acae2.util;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import wt.doc.WTDocument;
import wt.doc.WTDocumentHelper;
import wt.doc.WTDocumentMaster;
import wt.epm.EPMDocument;
import wt.fc.PersistenceHelper;
import wt.fc.QueryResult;
import wt.fc.ReferenceFactory;
import wt.folder.Folder;
import wt.folder.FolderHelper;
import wt.inf.container.WTContainer;
import wt.inf.container.WTContainerRef;
import wt.log4j.LogR;
import wt.org.WTOrganization;
import wt.part.WTPart;
import wt.pdmlink.PDMLinkProduct;
import wt.pds.StatementSpec;
import wt.query.QuerySpec;
import wt.query.SearchCondition;
import wt.type.ClientTypedUtility;
import wt.type.TypeDefinitionForeignKey;
import wt.type.TypeDefinitionReference;
import wt.util.WTException;
import wt.util.WTRuntimeException;
import wt.vc.config.LatestConfigSpec;

public class QueryUtil {

    private final static Logger LOGGER = LogR.getLogger(QueryUtil.class.getName());
    
    /**
     * Get Container By Name
     * 
     * @param name
     * @return
     * @throws WTException
     */
    public static WTContainer getContainerByName(String name) throws WTException {
        LOGGER.debug("> Start getContainerByName");
        LOGGER.debug("name: " + name);
        
        QuerySpec query = new QuerySpec(WTContainer.class);
        query.setAdvancedQueryEnabled(true);
        query.appendWhere(
                new SearchCondition(
                        WTContainer.class, WTContainer.NAME, SearchCondition.EQUAL, name), 
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        
        WTContainer container = null;
        
        if (result.hasMoreElements()) {
            container = (WTContainer) result.nextElement();
            LOGGER.debug("Found container!");
        }
        
        LOGGER.debug("> End getContainerByName");
        return container;
    }
    
    public static PDMLinkProduct getProductByName(String name) throws WTException {
        LOGGER.debug("> Start getProductByName");
        
        QuerySpec query = new QuerySpec(PDMLinkProduct.class);
        query.appendWhere(
                new SearchCondition(PDMLinkProduct.class, WTContainer.NAME, SearchCondition.EQUAL, name), 
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        
        PDMLinkProduct product = null;
        if (result.hasMoreElements()) {
            product = (PDMLinkProduct) result.nextElement();
            LOGGER.debug("Found product!");
        }
        
        LOGGER.debug("> End getProductByName");
        return product;
    }
    
    /**
     * Get organization by name
     * 
     * @param name
     * @return
     * @throws WTException
     */
    public static WTOrganization getOrganizationByName(String name) throws WTException {
        LOGGER.debug("> Start getOrganizationByName");
        
        QuerySpec query = new QuerySpec(WTOrganization.class);
        query.appendWhere(
                new SearchCondition(
                        WTOrganization.class, WTOrganization.NAME, SearchCondition.EQUAL, name), 
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        
        WTOrganization org = null;
        
        if (result.hasMoreElements()) {
            org = (WTOrganization) result.nextElement();
            LOGGER.debug("Found organization!");
        }
        
        LOGGER.debug("> End getOrganizationByName");
        return org;
    }
    
    /**
     * Get folder by name and container
     * 
     * @param name
     * @param containerRef
     * @return
     * @throws WTException
     */
    public static Folder getFolder(String name, WTContainerRef containerRef) throws WTException {
        LOGGER.debug("> Start getFolder");
        LOGGER.debug("name: " + name);
        LOGGER.debug("container: " + containerRef.getName());
        
        if (name == null || name.isEmpty()) {
            LOGGER.error("Folder is empty!");
            return null;
        }
        
        Folder folder = FolderHelper.service.getFolder(name, containerRef);
        if (folder != null) {
            LOGGER.debug("Found folder!");
        }
        
        LOGGER.debug("> End getFolder");
        return folder;
    }
    
    /**
     * 
     * @param number
     * @return
     * @throws WTException
     */
    public static WTPart getPartByNumber(String number) throws WTException {
        LOGGER.debug("> Start getPartByNumber");
        
        QuerySpec query = new QuerySpec(WTPart.class);
        query.setAdvancedQueryEnabled(true);
        query.appendWhere(
                new SearchCondition(WTPart.class, WTPart.NUMBER, SearchCondition.EQUAL, number), 
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        result = new LatestConfigSpec().process(result);
        
        WTPart part = null;
        if (result.hasMoreElements()) {
            part = (WTPart) result.nextElement();
            LOGGER.debug("Found part!");
        }
        
        LOGGER.debug("> End getPartByNumber");
        return part;
    }
    
    public static List<WTDocument> getDocumentsByType(String typeIdentifier) throws RemoteException, WTException {
        LOGGER.debug("> Start getDocumentsByType");
        LOGGER.debug("typeIdentifier: " + typeIdentifier);
        
        QuerySpec query = new QuerySpec(WTDocument.class);
        
        TypeDefinitionReference typeRef = ClientTypedUtility.getTypeDefinitionReference(typeIdentifier);
        query.appendWhere(
                new SearchCondition(
                        WTDocument.class,
                        WTDocument.TYPE_DEFINITION_REFERENCE + "." + TypeDefinitionReference.KEY + "." + TypeDefinitionForeignKey.BRANCH_ID,
                        SearchCondition.EQUAL,
                        typeRef.getKey().getBranchId()), 
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        result = new LatestConfigSpec().process(result);
        
        List<WTDocument> documentList = new ArrayList<WTDocument>();
        while (result.hasMoreElements()) {
            documentList.add((WTDocument) result.nextElement());
        }
        
        LOGGER.debug("documentList size: " + documentList.size());
        LOGGER.debug("> End getDocumentsByType");
        return documentList;
    }
    
    public static WTDocument getDocumentByNumber(String number) throws WTException {
        LOGGER.debug("> Start getDocumentByNumber");
        LOGGER.debug("number: " + number);
        
        QuerySpec query = new QuerySpec(WTDocument.class);
        query.appendWhere(
                new SearchCondition(
                        WTDocument.class,
                        WTDocument.NUMBER, 
                        SearchCondition.EQUAL,
                        number),
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        result = new LatestConfigSpec().process(result);
        
        WTDocument document = null;
        if (result.hasMoreElements()) {
            document = (WTDocument) result.nextElement();
            LOGGER.debug("Found document!");
        }
        
        LOGGER.debug("> End getDocumentByNumber");
        return document;
    }
    
    public static List<WTDocument> getChildDocuments(WTDocument parent) throws WTException {
        LOGGER.debug("> Start getChildDocuments");
        LOGGER.debug("parent: " + parent.getNumber());
        
        QueryResult childMasterResult = WTDocumentHelper.service.getUsesWTDocumentMasters(parent);
        List<WTDocument> childDocList = new ArrayList<WTDocument>();
        
        while (childMasterResult.hasMoreElements()) {
            WTDocumentMaster docMaster = (WTDocumentMaster) childMasterResult.nextElement();
            WTDocument doc = getDocumentByNumber(docMaster.getNumber());
            childDocList.add(doc);
        }
        
        LOGGER.debug("childDocList size: " + childDocList.size());
        LOGGER.debug("> End getChildDocuments");
        return childDocList;
    }
    
    public static WTDocument getParentDocument(WTDocument child) throws WTException {
        LOGGER.debug("> Start getParentDocument");
        LOGGER.debug("child: " + child.getNumber());
        
        QueryResult parentResult = WTDocumentHelper.service.getUsedByWTDocuments(
                (WTDocumentMaster) child.getMaster());
        
        LOGGER.debug("parentResult size: " + parentResult);
        
        WTDocument parent = null;
        if (parentResult.hasMoreElements()) {
            parent = (WTDocument) parentResult.nextElement();
        }
        
        LOGGER.debug("> End getParentDocument");
        return parent;
    }
    
    public static List<WTDocument> getChildDocumentsByOrder(WTDocument parent) throws WTException {
        LOGGER.debug("> Start getChildDocumentsByOrder");
        
        List<WTDocument> childDocuments = getChildDocuments(parent);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("before sort: ");
            for (WTDocument doc : childDocuments) {
                LOGGER.debug(doc.getNumber());
            }
        }
        
        WTDocument min = null;
        for (int i = 0; i < childDocuments.size(); i++) {
            min = childDocuments.get(i);
            
            for (int j = i + 1; j < childDocuments.size(); j++) {
                WTDocument jDoc = childDocuments.get(j);
                
                if (min.getNumber().compareTo(jDoc.getNumber()) > 0) {
                    min = jDoc;
                }
                
                childDocuments.remove(min);
                childDocuments.add(i, min);
            }
        }
        
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("after sort: ");
            for (WTDocument doc : childDocuments) {
                LOGGER.debug(doc.getNumber());
            }
        }
        
        LOGGER.debug("> End getChildDocumentsByOrder");
        return childDocuments;
    }
    
    public static WTDocument getDocumentByOid(String oid) throws WTRuntimeException, WTException {
        LOGGER.debug("> Start getDocumentByOid");
        
        ReferenceFactory factory = new ReferenceFactory();
        WTDocument doc = (WTDocument) factory.getReference(oid).getObject();
        
        if (doc != null) {
            LOGGER.debug("doc number: " + doc.getNumber());
        }
        
        LOGGER.debug("> End getDocumentByOid");
        return doc;
    }
    
    /**
     * Get EPMDocument By Number
     * 
     * @param number
     * @return
     * @throws WTException
     */
    public static EPMDocument getEPMDocumentByNumber(String number) throws WTException {
        LOGGER.debug("> Start getEPMDocumentByNumber");
        LOGGER.debug("number: " + number);
        
        QuerySpec query = new QuerySpec(EPMDocument.class);
        query.appendWhere(
                new SearchCondition(
                		EPMDocument.class,
                		EPMDocument.NUMBER, 
                        SearchCondition.EQUAL,
                        number),
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        result = new LatestConfigSpec().process(result);
        
        EPMDocument document = null;
        if (result.hasMoreElements()) {
            document = (EPMDocument) result.nextElement();
            LOGGER.debug("Found epmDocument!");
        }
        
        LOGGER.debug("> End getEPMDocumentByNumber");
        return document;
    }
    
    /**
     * 
     * @param number
     * @return
     * @throws WTException
     */
    public static List<WTPart> getPartsByNumber(String number) throws WTException {
        LOGGER.debug("> Start getPartsByNumber");
        
        List<WTPart> list = new ArrayList<WTPart>();
        QuerySpec query = new QuerySpec(WTPart.class);
        query.setAdvancedQueryEnabled(true);
        query.appendWhere(
                new SearchCondition(WTPart.class, WTPart.NUMBER, SearchCondition.EQUAL, number), 
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        
        WTPart part = null;
        while (result.hasMoreElements()) {
            part = (WTPart) result.nextElement();
            list.add(part);
            LOGGER.debug("Found part!");
        }
        
        LOGGER.debug("> End getPartsByNumber");
        return list;
    }
    
    public static List<WTDocument> getDocumentsByNumber(String number) throws WTException {
        LOGGER.debug("> Start getDocumentsByNumber");
        LOGGER.debug("number: " + number);
        
        List<WTDocument> list = new ArrayList<WTDocument>();
        QuerySpec query = new QuerySpec(WTDocument.class);
        query.appendWhere(
                new SearchCondition(
                        WTDocument.class,
                        WTDocument.NUMBER, 
                        SearchCondition.EQUAL,
                        number),
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        
        WTDocument document = null;
        while (result.hasMoreElements()) {
            document = (WTDocument) result.nextElement();
            list.add(document);
            LOGGER.debug("Found document!");
        }
        
        LOGGER.debug("> End getDocumentsByNumber");
        return list;
    }
    
    /**
     * Get EPMDocuments By Number
     * 
     * @param number
     * @return
     * @throws WTException
     */
    public static List<EPMDocument> getEPMDocumentsByNumber(String number) throws WTException {
        LOGGER.debug("> Start getEPMDocumentsByNumber");
        LOGGER.debug("number: " + number);
        
        List<EPMDocument> list = new ArrayList<EPMDocument>();
        QuerySpec query = new QuerySpec(EPMDocument.class);
        query.appendWhere(
                new SearchCondition(
                		EPMDocument.class,
                		EPMDocument.NUMBER, 
                        SearchCondition.EQUAL,
                        number),
                new int[]{});
        QueryResult result = PersistenceHelper.manager.find((StatementSpec) query);
        
        EPMDocument document = null;
        while (result.hasMoreElements()) {
            document = (EPMDocument) result.nextElement();
            list.add(document);
            LOGGER.debug("Found epmDocument!");
        }
        
        LOGGER.debug("> End getEPMDocumentsByNumber");
        return list;
    }
    
    
}
